package com.rui.observer.main;

import com.google.common.eventbus.EventBus;
import com.rui.observer.model.guava.GuavaWeixinUser;
import com.rui.observer.model.jdk.JdkSubject;
import com.rui.observer.model.jdk.JdkWeixinUser;
import com.rui.observer.model.push.Observable;
import com.rui.observer.model.push.Subject;
import com.rui.observer.model.push.WeixinUser;

/**
 * 观察者模式（Observer Mode）
 * <p>
 * <p>
 * 观察者模式，又叫发布-订阅（Publish/Subscribe）模式，模型-视图（Model/View）模式，源-监听器（Source/Listener）模式或从属者（Dependents）模式。定义一种一对多的依赖关系，一个主题对象可被多个观察者同时监听，使得每当主题对象状态变化时，所有依赖于它的对象都会得到通知并被自动更新。
 * <p>
 * <p>
 * 适用场景：
 * 当一个抽象模型包含两个方面内容，其中一个方面依赖于另一个方面。
 * 其他一个或多个对象的变化依赖于另一个对象的变化。
 * 实现类似广播机制的功能，无需知道具体收听者，只需分发广播，系统中感兴趣的对象会自动接收该广播。
 * 多层级嵌套使用，形成一种链式触发机制，使得事件具备跨域（跨越两种观察者类型）通知。
 * <p>
 * 优点：
 * 观察者和被观察者是松耦合（抽象耦合）的，符合依赖倒置原则。
 * 分离了表示层（观察者）和数据逻辑层（被观察者），并且建立了一套触发机制，使得数据的变化可以相应到多个表示层上。
 * 实现了一对多的通讯机制，支持事件注册机制，支持兴趣分发机制，当被观察者触发事件时，只有感兴趣的观察者可以接收到通知。
 * <p>
 * 缺点：
 * 如果观察者数量过多，则事件通知会耗时较长。
 * 事件通知呈线性关系，如果其中一个观察者处理事件卡壳，会影响后续的观察者接收该事件。
 * 如果观察者和被观察者之间存在循环依赖，则可能造成两者之间的循环调用，导致系统崩溃。
 *
 * @author ZhangRui
 * @date 2023/03/03 15:37
 **/
public class Main {


    public static void main(String[] args) {

        test1();

        test2();

        test3();
    }


    /**
     * 通过一个微信用户（观察者）订阅公众号（被观察者）接收公众号推送消息的例子来进行简单的代码实现
     *
     * @param null
     * @return
     * @author ZhangRui
     * @date 2023/3/3 15:43
     */
    public static void test1() {

        WeixinUser user1 = new WeixinUser("张三");
        WeixinUser user2 = new WeixinUser("李四");
        WeixinUser user3 = new WeixinUser("王五");

        Observable o = new Subject();
        o.add(user1);
        o.add(user2);
        o.add(user3);
        o.notify("薛之谦演唱会要来到广州啦!");

        // 运行结果
        // 张三接收到了消息(观察到了):薛之谦演唱会要来到广州啦!
        // 李四接收到了消息(观察到了):薛之谦演唱会要来到广州啦!
        // 王五接收到了消息(观察到了):薛之谦演唱会要来到广州啦!
    }

    /**
     * 通过微信用户订阅公众号的例子进行代码实现
     *
     * @param null
     * @return
     * @author ZhangRui
     * @date 2023/3/3 15:54
     */
    public static void test2() {

        JdkWeixinUser user1 = new JdkWeixinUser("张三");
        JdkWeixinUser user2 = new JdkWeixinUser("李四");
        JdkWeixinUser user3 = new JdkWeixinUser("王五");

        JdkSubject subject = new JdkSubject("演唱会消息发布");
        subject.addObserver(user1);
        subject.addObserver(user2);
        subject.addObserver(user3);
        subject.notifyMessage("薛之谦演唱会要来到广州啦!");
        // 返回结果
        // 演唱会消息发布公众号发布消息:薛之谦演唱会要来到广州啦!请关注用户留意接收!
        // 王五关注了公众号(被观察者):演唱会消息发布,接收到消息:薛之谦演唱会要来到广州啦!
        // 李四关注了公众号(被观察者):演唱会消息发布,接收到消息:薛之谦演唱会要来到广州啦!
        // 张三关注了公众号(被观察者):演唱会消息发布,接收到消息:薛之谦演唱会要来到广州啦!

    }

    /**
     * @Description: Google的Guava实现消息订阅
     * @Author: ZhangRui
     * @Date: 2023/3/3 16:02
     * @Version: 1.0
     */
    public static void test3() {
        // 消息总线
        EventBus eventBus = new EventBus();
        eventBus.register(new GuavaWeixinUser("张三"));
        eventBus.register(new GuavaWeixinUser("李四"));
        eventBus.post("薛之谦演唱会要来到广州啦!");
        // 返回结果
        // 张三接收到消息:薛之谦演唱会要来到广州啦!
        // 李四接收到消息:薛之谦演唱会要来到广州啦!
    }

}
